﻿using System;
using System.Collections.Generic;

namespace Bridge.Base.Utilities
{
    public static class IEnumerableExtensions
    {
        /// <summary>
        /// Combines all of the values in an IEnumerable into a concenated string.
        /// </summary>
        /// <typeparam name="T">Type of items to concenate.</typeparam>
        /// <param name="self">IEnumerable to concenate.</param>
        /// <returns>String combined</returns>
        /// <exception cref="ArgumentNullException">Thrown if self is null.</exception>
        public static string Combine<T>(this IEnumerable<T> self)
        {
            if (self == null) throw new ArgumentNullException("self");

            return Combine<T>(self, input => input.ToString(), ",");
        }

        /// <summary>
        /// Combines all of the values in an IEnumerable into a concenated string.
        /// </summary>
        /// <typeparam name="T">Type of items to concenate.</typeparam>
        /// <param name="self">IEnumerable to concenate.</param>
        /// <param name="appendString">String to append at the end of each value.</param>
        /// <returns>String combined</returns>
        /// <exception cref="ArgumentNullException">Thrown if self or appendString is null.</exception>
        public static string Combine<T>(this IEnumerable<T> self, string appendString)
        {
            if (self == null) throw new ArgumentNullException("self");
            if (appendString == null) throw new ArgumentNullException("appendString");

            return Combine<T>(self, input => input.ToString(), appendString);
        }

        /// <summary>
        /// Combines all of the values in an IEnumerable into a concenated string.
        /// </summary>
        /// <typeparam name="T">Type of items to concenate.</typeparam>
        /// <param name="self">IEnumerable to concenate.</param>
        /// <param name="format">Format method to use to convert the items into strings.</param>
        /// <returns>String combined</returns>
        /// <exception cref="ArgumentNullException">Thrown if self or format is null.</exception>
        public static string Combine<T>(this IEnumerable<T> self, Func<T, string> format)
        {
            if (self == null) throw new ArgumentNullException("self");
            if (format == null) throw new ArgumentNullException("format");

            return Combine<T>(self, format, ",");
        }

        /// <summary>
        /// Combines all of the values in an IEnumerable into a concenated string.
        /// </summary>
        /// <typeparam name="T">Type of items to concenate.</typeparam>
        /// <param name="self">IEnumerable to concenate.</param>
        /// <param name="appendString">String to append at the end of each value.</param>
        /// <param name="format">Format method to use to convert the items into strings.</param>
        /// <returns>String combined</returns>
        /// <exception cref="ArgumentNullException">Thrown if self, format or appendString is null.</exception>
        public static string Combine<T>(this IEnumerable<T> self, Func<T, string> format, string appendString)
        {
            if (self == null) throw new ArgumentNullException("self");
            if (format == null) throw new ArgumentNullException("format");
            if (appendString == null) throw new ArgumentNullException("appendString");

            string combineString = "";
            foreach (T item in self)
            {
                if (combineString.Length > 0)
                {
                    combineString += appendString;
                }
                combineString += format.Invoke(item);
            }
            return combineString;
        }
    }
}
